#include "DigisparkOLEDM.h"
#include "font8x16.h"

//const uint8_t ssd1306_12864_init_sequence [] PROGMEM =
//{
//  0xAE,      // Display OFF (sleep mode)
//  0x20, 0b00,   // Set Memory Addressing Mode
//  // 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
//  // 10=Page Addressing Mode (RESET); 11=Invalid
//  0xB0,     // Set Page Start Address for Page Addressing Mode, 0-7
//  0xC8,     // Set COM Output Scan Direction
//  0x00,     // ---set low column address
//  0x10,     // ---set high column address
//  0x40,     // --set start line address
//  0x81, 0x3F,   // Set contrast control register
//  0xA1,     // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
//  0xA6,     // Set display mode. A6=Normal; A7=Inverse
//  0xA8, 0x3F,   // Set multiplex ratio(1 to 64)
//  0xA4,     // Output RAM to Display
//  // 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
//  0xD3, 0x00,   // Set display offset. 00 = no offset
//  0xD5,     // --set display clock divide ratio/oscillator frequency
//  0xF0,     // --set divide ratio
//  0xD9, 0x22,   // Set pre-charge period
//  0xDA, 0x12,   // Set com pins hardware configuration
//  0xDB,     // --set vcomh
//  0x20,     // 0x20,0.77xVcc
//  0x8D, 0x14,   // Set DC-DC enable
//  0xAF      // Display ON in normal mode
//};

const uint8_t ssd1306_12832_init_sequence [] PROGMEM =
{
  0xae,// Display OFF (sleep mode)
  0x00,// set low column address
  0x10,// set high column address
  0x00,// set display start line
  0xb0,// set page address
  0x81,// contract address
  0xff,// 128
  0xa1,// set segment remap
  0xa6,// nomal
  0xa8,// multiplex ratio
  0x1f,// duty =1/32
  0xc8,// com scan direction
  0xd3,// set dislpay offset
  0x00,
  0xd5,// set osc division
  0x80,
  0xd9,// set pre-charge period
  0x04,
  0xda,// set com pins
  0x00,
  0xdb,// set vcomh
  0x30,
  0x8d,// set charge pump enable
  0x14,
  0xaf // dislpay on
};

uint8_t oledX, oledY = 0;
SSD1306Device::SSD1306Device(void)
{
}
void SSD1306Device::begin(void)
{
  Wire.begin();
  for (uint8_t i = 0; i < sizeof (ssd1306_12832_init_sequence); i++)
  {
    ssd1306_send_command(pgm_read_byte(&ssd1306_12832_init_sequence[i]));
  }
  clear();
}
void SSD1306Device::ssd1306_send_command_start(void)
{
  Wire.beginTransmission(SSD1306);
  Wire.write(0x00);
}
void SSD1306Device::ssd1306_send_command_stop(void)
{
  Wire.endTransmission();
}
void SSD1306Device::ssd1306_send_data_byte(uint8_t byte)
{
  if (Wire.writeAvailable())
  {
    ssd1306_send_data_stop();
    ssd1306_send_data_start();
  }
  Wire.write(byte);
}
void SSD1306Device::ssd1306_send_command(uint8_t command)
{
  ssd1306_send_command_start();
  Wire.write(command);
  ssd1306_send_command_stop();
}
void SSD1306Device::ssd1306_send_data_start(void)
{
  Wire.beginTransmission(SSD1306);
  Wire.write(0x40);
}
void SSD1306Device::ssd1306_send_data_stop(void)
{
  Wire.endTransmission();
}
void SSD1306Device::setCursor(uint8_t x, uint8_t y)
{
  ssd1306_send_command_start();
  Wire.write(0xb0 + y);
  Wire.write(((x & 0xf0) >> 4) | 0x10);
  Wire.write((x & 0x0f) | 0x01);
  ssd1306_send_command_stop();
  oledX = x;
  oledY = y;
}
void SSD1306Device::clear(void)
{
  fill(0x00);
}
void SSD1306Device::fill(uint8_t fill)
{
  uint8_t m, n;
  for (m = 0; m < 8; m++)
  {
    ssd1306_send_command(0xb0 + m);
    ssd1306_send_command(0x00);
    ssd1306_send_command(0x10);
    ssd1306_send_data_start();
    for (n = 0; n < 128; n++)
    {
      ssd1306_send_data_byte(fill);
    }
    ssd1306_send_data_stop();
  }
  setCursor(0, 0);
}
size_t SSD1306Device::write(byte c)
{
  uint8_t i = 0;
  uint8_t ci = c - 32;
  if (c == '\r')
    return 1;
  if (c == '\n')
  {
    oledY += 2;
    if ( oledY > 6)
      oledY = 6;
    setCursor(0, oledY);
    return 1;
  }
  if (oledX > 120)
  {
    oledX = 0;
    oledY += 2;
    if ( oledY > 6)
      oledY = 6;
    setCursor(oledX, oledY);
  }
  ssd1306_send_data_start();
  for (i = 0; i < 8; i++)
  {
    Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i]));
  }
  ssd1306_send_data_stop();
  setCursor(oledX, oledY + 1);
  ssd1306_send_data_start();
  for (i = 0; i < 8; i++)
  {
    Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i + 8]));
  }
  ssd1306_send_data_stop();
  setCursor(oledX + 8, oledY - 1);
  return 1;
}
SSD1306Device oled;

